﻿namespace Raven
{
    public enum WeaponType
    {
        type_none,
        type_rail_gun,
        type_rocket_launcher,
        type_shotgun,
        type_blaster,
    }

    public abstract class RavenWeapon
    {
        //a weapon is always (in this game) carried by a bot
        protected RavenBot _owner;

        //an enumeration indicating the type of weapon
        protected WeaponType _type;

        //fuzzy logic is used to determine the desirability of a weapon. Each weapon
        //owns its own instance of a fuzzy module because each has a different rule 
        //set for inferring desirability.
        protected FuzzyModule _fuzzyModule;

        //amount of ammo carried for this weapon
        protected int _numRoundsLeft;

        //maximum number of rounds a bot can carry for this weapon
        protected int _maxRoundsCarried;

        //the number of times this weapon can be fired per second
        protected Fix _rateOfFire;

        //the earliest time the next shot can be taken
        protected Fix _timeNextAvailable;

        //this is used to keep a local copy of the previous desirability score
        //so that we can give some feedback for debugging
        protected Fix _lastDesirabilityScore;

        //this is the prefered distance from the enemy when using this weapon
        protected Fix _idealRange;

        //the max speed of the projectile this weapon fires
        protected Fix _maxProjectileSpeed;

        //The number of times a weapon can be discharges depends on its rate of fire.
        //This method returns true if the weapon is able to be discharged at the 
        //current time. (called from ShootAt() )
        protected bool isReadyForNextShot()
        {
            if (_owner.GetWorld().GetTimer().currentTime > _timeNextAvailable)
            {
                return true;
            }

            return false;
        }

        //this is called when a shot is fired to update m_dTimeNextAvailable
        protected void UpdateTimeWeaponIsNextAvailable()
        {
            _timeNextAvailable = _owner.GetWorld().GetTimer().currentTime + 1 / _rateOfFire;
        }

        //this method initializes the fuzzy module with the appropriate fuzzy 
        //variables and rule base.
        protected abstract void InitializeFuzzyModule();

        public RavenWeapon(WeaponType TypeOfGun,
            int DefaultNumRounds,
            int MaxRoundsCarried,
            Fix RateOfFire,
            Fix IdealRange,
            Fix ProjectileSpeed,
            RavenBot owner)
        {
            _type = TypeOfGun;
            _numRoundsLeft = DefaultNumRounds;
            _owner = owner;
            _rateOfFire = RateOfFire;
            _maxRoundsCarried = MaxRoundsCarried;
            _lastDesirabilityScore = 0;
            _idealRange = IdealRange;
            _maxProjectileSpeed = ProjectileSpeed;
            _timeNextAvailable = _owner.GetWorld().GetTimer().currentTime;
        }

        public abstract void Destroy();


        //this method aims the weapon at the given target by rotating the weapon's
        //owner's facing direction (constrained by the bot's turning rate). It returns  
        //true if the weapon is directly facing the target.
        public bool AimAt(Vector2 target)
        {
            return _owner.RotateFacingTowardPosition(target);
        }

        //this discharges a projectile from the weapon at the given target position
        //(provided the weapon is ready to be discharged... every weapon has its
        //own rate of fire)
        public abstract void ShootAt(Vector2 pos);

        //this method returns a value representing the desirability of using the
        //weapon. This is used by the AI to select the most suitable weapon for
        //a bot's current situation. This value is calculated using fuzzy logic
        public abstract Fix GetDesirability(Fix DistToTarget);

        //returns the desirability score calculated in the last call to GetDesirability
        //(just used for debugging)
        public Fix GetLastDesirabilityScore()
        {
            return _lastDesirabilityScore;
        }

        //returns the maximum speed of the projectile this weapon fires
        public Fix GetMaxProjectileSpeed()
        {
            return _maxProjectileSpeed;
        }

        //returns the number of rounds remaining for the weapon
        public int NumRoundsRemaining()
        {
            return _numRoundsLeft;
        }

        public void DecrementNumRounds()
        {
            if (_numRoundsLeft > 0) --_numRoundsLeft;
        }

        public void IncrementRounds(int num)
        {
            _numRoundsLeft+=num;
            _numRoundsLeft = FixMath.Clamp(_numRoundsLeft, 0, _maxRoundsCarried);
        }

        public WeaponType GetWeaponType()
        {
            return _type;
        }

        public Fix GetIdealRange()
        {
            return _idealRange;
        }
    }
}